package com.emm.yixun.website.service.marketing;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.emm.yixun.common.model.BaseCodeType;
import com.emm.yixun.common.model.BaseCodeValue;
import com.emm.yixun.common.model.BaseCodeValueInfo;
import com.emm.yixun.common.model.Customer;
import com.emm.yixun.common.model.CustomerError;
import com.emm.yixun.common.model.PriceScheme;
import com.emm.yixun.common.model.PriceSchemeDetail;
import com.emm.yixun.common.model.Project;
import com.emm.yixun.common.model.ProjectBuilding;
import com.emm.yixun.common.model.ProjectPremises;
import com.emm.yixun.common.model.ProjectRoom;
import com.emm.yixun.common.model.ProjectUnit;
import com.emm.yixun.common.model.User;
import com.emm.yixun.common.model.dto.BaseCodeTypeDto;
import com.emm.yixun.common.model.dto.BaseCodeValueDto;
import com.emm.yixun.common.model.dto.CustomerDto;
import com.emm.yixun.common.model.dto.MarketingModel;
import com.emm.yixun.common.model.dto.NeedReceiveRefundDto;
import com.emm.yixun.common.model.dto.ProceedsDto;
import com.emm.yixun.common.model.dto.ProjectBuildingDto;
import com.emm.yixun.common.model.dto.ProjectPremisesDto;
import com.emm.yixun.common.model.dto.ProjectRoomDto;
import com.emm.yixun.common.model.dto.ProjectRoomPriceDto;
import com.emm.yixun.common.model.dto.ProjectUnitDto;
import com.emm.yixun.common.model.dto.RoomChangeHistoryDto;
import com.emm.yixun.common.model.dto.SignedDto;
import com.emm.yixun.common.model.dto.SubscribeDto;
import com.emm.yixun.common.model.dto.TransactionRelationDto;
import com.emm.yixun.common.model.dto.UserDto;
import com.emm.yixun.common.model.enums.AuditStatusEnum;
import com.emm.yixun.common.model.enums.BusinessFlagEnum;
import com.emm.yixun.common.model.enums.BusinessStatusEnum;
import com.emm.yixun.common.model.enums.BusinessTypeEnum;
import com.emm.yixun.common.model.enums.ContactTypeEnum;
import com.emm.yixun.common.model.enums.DealCategoryEnum;
import com.emm.yixun.common.model.enums.DelFlagEnum;
import com.emm.yixun.common.model.enums.DocTypeEnum;
import com.emm.yixun.common.model.enums.FloorTypeEnum;
import com.emm.yixun.common.model.enums.HousingFundTypeEnum;
import com.emm.yixun.common.model.enums.PaymentMethodEnum;
import com.emm.yixun.common.model.enums.RelationTypeEnum;
import com.emm.yixun.common.model.enums.RoomStatusEnum;
import com.emm.yixun.common.model.enums.SubscribeBusinessStatusEnum;
import com.emm.yixun.common.model.enums.UserStatusEnum;
import com.emm.yixun.common.response.Response;
import com.emm.yixun.common.response.ResponseList;
import com.emm.yixun.common.utils.MathUtil;
import com.emm.yixun.common.utils.VerifyIDNumber;
import com.emm.yixun.customer.service.CustomerErrorServiceFacade;
import com.emm.yixun.customer.service.CustomerServiceFacade;
import com.emm.yixun.customer.service.SignedServiceFacade;
import com.emm.yixun.customer.service.SubscribeServiceFacade;
import com.emm.yixun.customer.service.TransactionRelationServiceFacade;
import com.emm.yixun.estate.service.ProjectBuildingServiceFacade;
import com.emm.yixun.estate.service.ProjectPremisesServiceFacade;
import com.emm.yixun.estate.service.ProjectRoomServiceFacade;
import com.emm.yixun.estate.service.ProjectServiceFacade;
import com.emm.yixun.estate.service.ProjectUnitServiceFacade;
import com.emm.yixun.marketing.service.NeedReceiveRefundServiceFacade;
import com.emm.yixun.marketing.service.PriceSchemeDetailServiceFacade;
import com.emm.yixun.marketing.service.PriceSchemeServiceFacade;
import com.emm.yixun.marketing.service.ProceedsServiceFacade;
import com.emm.yixun.marketing.service.RoomChangeHistoryServiceFacade;
import com.emm.yixun.system.service.BaseCodeTypeServiceFacade;
import com.emm.yixun.system.service.BaseCodeValueServiceFacade;
import com.emm.yixun.system.service.UserServiceFacade;
import com.emm.yixun.website.constant.EhcacheConstant;
import com.emm.yixun.website.service.CacheUtils;
import com.emm.yixun.website.vo.CustomerImportVo;

/**
 * 交易数据导入
 * @author junze.liu
 */
@Service
public class MarketingImpServiceImpl implements MarketingImpService{
	
	@Autowired
	private UserServiceFacade userServiceFacade;
	
	@Autowired
	private CustomerServiceFacade customerServiceFacade;
	
	@Autowired
	private ProjectRoomServiceFacade projectRoomServiceFacade;
	
	@Autowired
	private ProjectUnitServiceFacade projectUnitServiceFacade;
	
	@Autowired
	private ProjectBuildingServiceFacade projectBuildingServiceFacade;
	
	@Autowired
	private ProjectPremisesServiceFacade projectPremisesServiceFacade;
	
	@Autowired
	private CustomerErrorServiceFacade customerErrorServiceFacade;
	
	@Autowired
	private ProjectServiceFacade projectServiceFacade;
	
	@Autowired
	private PriceSchemeDetailServiceFacade priceSchemeDetailServiceFacade;
	
	@Autowired
	private PriceSchemeServiceFacade priceSchemeServiceFacade;
	
	@Autowired
	private SubscribeServiceFacade subscribeServiceFacade;
	
	@Autowired
	private TransactionRelationServiceFacade transactionRelationServiceFacade;
	
	@Autowired
	private NeedReceiveRefundServiceFacade needReceiveRefundServiceFacade;
	
	@Autowired
	private ProceedsServiceFacade proceedsServiceFacade;
	
	@Autowired
	private SignedServiceFacade signedServiceFacade;
	
	@Autowired
	private BaseCodeTypeServiceFacade baseCodeTypeServiceFacade;
	
	@Autowired
	private BaseCodeValueServiceFacade baseCodeValueServiceFacade;
	
	@Autowired
	private RoomChangeHistoryServiceFacade roomChangeHistoryServiceFacade;
	
	@Autowired
	private CacheUtils cacheUtils;
	
	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
	
	/**
	 * 新增认购数据
	 * @return
	 * @throws Exception 
	 */
	@Override
	public Response<CustomerImportVo> addSubscribe(List<MarketingModel> list, Long projectId, User user, int type) throws Exception{
		Response<CustomerImportVo> response = new Response<CustomerImportVo>();
		List<MarketingModel> errorList = new ArrayList<MarketingModel>();
		Project pro = getProjectInfo(projectId); //获取项目信息
		if(pro == null) {
			response.fail("0000", "未获取到项目信息");
			return response;
		}
		
		getCustomerList(projectId); //获取客户列表
		getUserList(pro.getMerchantId()); //获取经纪人列表
		getDocumentTypeId(projectId); //获取证件类型
		
		BigDecimal zero = new BigDecimal("0");
		int row = 0; //记录错误行数
		for(MarketingModel model : list) {
			row++;
			Map<String, Object> resultMap = validateSubscribeModel(model, projectId, type);
			//数据有误时，跳过本次循环
			if(resultMap.get("error") != null) {
				model.setErrorInfo("第"+(row+1)+"行 "+resultMap.get("error").toString());
				errorList.add(model);
				continue;
			}
			Long userId = Long.parseLong(resultMap.get("userId").toString());
			String userCode = resultMap.get("userCode").toString();
			Long roomId = Long.parseLong(resultMap.get("roomId").toString());
			BigDecimal calculateArea = new BigDecimal(resultMap.get("calculateArea").toString());
			BigDecimal innerArea = new BigDecimal(resultMap.get("innerArea").toString());
			Long customerId = Long.parseLong(resultMap.get("customerId").toString());
			String dealCategory = resultMap.get("dealCategory").toString();
			//组装认购入参
			SubscribeDto subDto = new SubscribeDto();
			subDto.setFloorType(FloorTypeEnum.DISCOUNT_AMOUNT.getNo()); //折扣类型
			subDto.setCustomerId(customerId); //客户ID
			subDto.setRoomId(roomId); //房号ID
			subDto.setCalculateArea(type == 2?new BigDecimal("1"): calculateArea); //建筑面积
			subDto.setSubscribeCode(model.getSubscribeCode()); //认购编号
			subDto.setPayDepositMoney(zero); //认筹金额
			subDto.setSubscribeAmount(new BigDecimal(model.getDiscountAfterPrice())); //折后金额
			//签约单价
			if(calculateArea.compareTo(zero) > 0) {
				subDto.setSubscribePrice(subDto.getSubscribeAmount().divide(calculateArea, 2, BigDecimal.ROUND_HALF_UP)); 
			} else {
				subDto.setSubscribePrice(subDto.getSubscribeAmount());
			}
			subDto.setDepositReceivable(new BigDecimal(resultMap.get("depositReceivable").toString())); //认购金
			subDto.setDiscountNote(model.getDiscountNote()); //折扣说明
			subDto.setSubscribeDate(sdf.parse(resultMap.get("subscribeDate").toString())); //认购日期
			subDto.setDidTime(subDto.getSubscribeDate()); //经办时间
			subDto.setCheckDate(subDto.getSubscribeDate()); //审核日期
			subDto.setConversionSignDate(sdf.parse(resultMap.get("conversionSignDate").toString())); //认购转签约日期
			subDto.setDueTime(subDto.getConversionSignDate()); //移动端用这个字段标示为认购转签约日期
			subDto.setRemark(model.getRemark()); //备注
			subDto.setDealCategory(dealCategory); //成交类别
			subDto.setUserCode(userCode); //经纪人code
			subDto.setProjectId(projectId); //项目id
			subDto.setProjectCode(pro.getProjectCode()); //项目code
			subDto.setAccessCode(pro.getProjectCode()); //项目code
			subDto.setBusinessStatus(SubscribeBusinessStatusEnum.SUBSCRIBE.getNo()); //认购状态
			subDto.setAuditStatus(AuditStatusEnum.SUCCESS.getNo()); //审核状态
			subDto.setDiscountApproval("0"); //折扣审批
			ProjectRoomPriceDto priceDto = getPriceSchemeDetail(roomId, calculateArea, innerArea); //获取价格方案
			subDto.setConversionPrice(priceDto.getCalculateUnitPrice()); //折前单价
			subDto.setLumpsumPrice(priceDto.getTotalPrice()); //折前总价
			subDto.setDiscountAmount(priceDto.getTotalPrice().subtract(subDto.getSubscribeAmount())); //折扣金额
			subDto.setDiscountRate(new BigDecimal("0")); //折扣比例
			subDto.setMerchantId(user.getMerchantId()); //商户ID
			subDto.setCreateUserId(user.getId()); //创建人
			subDto.setUserCode(user.getUserCode()); //经纪人code
			subDto.setDelFlag(DelFlagEnum.UNDEL.getNo()); //是否删除
			subDto.setUpdateUserId(user.getId()); //修改人
			subDto.setUpdateTime(new Date()); //修改时间
			Response<SubscribeDto> resSub = subscribeServiceFacade.save(subDto);
			if(resSub.isSuccess()) {
				SubscribeDto dto = resSub.getEntity();
				//修改房间状态
				updateRoomInfo(dto.getRoomId(), RoomStatusEnum.BUY.getNo());
				//经纪人信息
				saveAgent(dto.getId(), projectId, pro.getProjectCode(), dto.getDealCategory(), 
						dto.getMerchantId(), userId, userCode, user.getId(), RelationTypeEnum.SUBSCRIBE.getNo());
				String isHaveSubscribeAmount = "1"; //是否已收认购金，默认为否
				if("是".equals(model.getIsHaveSubscribeAmount())) {
					isHaveSubscribeAmount = "0";
				}
				//保存待收信息
				saveNeedReceiveRefund(resSub.getEntity(), isHaveSubscribeAmount, userId, "0");
				//更新客户信息
				updateCustomerInfo(customerId, model.getCustomerName(), resultMap.get("documentType").toString(), 
						model.getDocumentNumber(), model.getContactAddress(), model.getPostcode());
				//认购房源变更记录
				subscribeRoomChangeHistory(dto);
			}
 		}
		//保存导入错误的信息
		String batchId = UUID.randomUUID().toString(); //批次号
		if(errorList.size()>0){
			saveErrorInfo(errorList, user.getId(), user.getMerchantId(), batchId);
		}
		CustomerImportVo ci = new CustomerImportVo();
		ci.setSuccessCount(list.size() - errorList.size());
		ci.setErrorCount(errorList.size());
		ci.setBatchId(batchId);
		response.success(ci);
		return response;
	}
	
	/**
	 * 新增签约数据
	 * @return
	 * @throws Exception 
	 */
	@Override
	public Response<CustomerImportVo> addSigned(List<MarketingModel> list, Long projectId, User user, int type) throws Exception{
		Response<CustomerImportVo> response = new Response<CustomerImportVo>();
		List<MarketingModel> errorList = new ArrayList<MarketingModel>();
		Project pro = getProjectInfo(projectId); //获取项目信息
		if(pro == null) {
			response.fail("0000", "未获取到项目信息");
			return response;
		}
		
		getCustomerList(projectId); //获取客户列表
		getUserList(pro.getMerchantId()); //获取经纪人列表
		getDocumentTypeId(projectId); //获取证件类型
		
		int row = 0; //记录错误行数
		for(MarketingModel model : list) {
			row++;
			Map<String, Object> resultMap = validateSignedModel(model, projectId, type);
			//数据有误时，跳过本次循环
			if(resultMap.get("error") != null) {
				model.setErrorInfo("第"+(row+1)+"行 "+resultMap.get("error").toString());
				errorList.add(model);
				continue;
			}
			Long userId = Long.parseLong(resultMap.get("userId").toString());
			Long roomId = Long.parseLong(resultMap.get("roomId").toString());
			BigDecimal calculateArea = new BigDecimal(resultMap.get("calculateArea").toString());
			BigDecimal innerArea = new BigDecimal(resultMap.get("innerArea").toString());
			Long customerId = Long.parseLong(resultMap.get("customerId").toString());
			String userCode = resultMap.get("userCode").toString();
			String dealCategory = resultMap.get("dealCategory").toString();
			
			SignedDto signedDto = new SignedDto();
			signedDto.setSignCode(model.getSignCode()); //签约编号
			signedDto.setFloorType(FloorTypeEnum.DISCOUNT_AMOUNT.getNo()); //折扣类型
			signedDto.setCustomerId(customerId); //客户ID
			signedDto.setRoomId(roomId); //房号ID
			signedDto.setPayDepositMoney(new BigDecimal("0")); //认筹金额
			signedDto.setSubscribeAmount(new BigDecimal("0")); //认购金
			signedDto.setContactType(resultMap.get("contactType").toString()); //合同类型
			signedDto.setCalculateArea(calculateArea); //建筑面积
			signedDto.setDealCategory(dealCategory); //成交类别
			signedDto.setUserCode(userCode); //经纪人code
			signedDto.setProjectId(projectId); //项目id
			signedDto.setProjectCode(pro.getProjectCode()); //项目code
			signedDto.setAccessCode(pro.getProjectCode()); //项目code
			signedDto.setBusinessStatus(BusinessStatusEnum.SIGNED.getNo()); //认购状态
			signedDto.setAuditStatus(AuditStatusEnum.SUCCESS.getNo()); //审核状态
			ProjectRoomPriceDto priceDto = getPriceSchemeDetail(roomId, calculateArea, innerArea); //获取价格方案
			signedDto.setSignAmount(new BigDecimal(model.getDiscountAfterPrice())); //合同金额
			signedDto.setDiscountAfterPrice(signedDto.getSignAmount()); //折后总价
			if(calculateArea.compareTo(new BigDecimal("0")) > 0) {
				signedDto.setSignPrice(signedDto.getSignAmount().divide(calculateArea, 2, BigDecimal.ROUND_HALF_UP));
			} else {
				signedDto.setSignPrice(signedDto.getSignAmount());
			}
			signedDto.setConversionPrice(priceDto.getCalculateUnitPrice()); //折前单价
			signedDto.setLumpsumPrice(priceDto.getTotalPrice()); //折前总价
			signedDto.setDiscountAmount(priceDto.getTotalPrice().subtract(signedDto.getSignAmount())); //折扣金额
			signedDto.setReceivableAmount(signedDto.getSignAmount()); //应收金额
			signedDto.setDiscountRate(new BigDecimal("0")); //折扣比例
			signedDto.setDecorationMoney(new BigDecimal("0")); //装修款
			signedDto.setPaymentMethod(resultMap.get("paymentMethod").toString());
			signedDto.setMerchantId(user.getMerchantId()); //商户ID
			signedDto.setCreateUserId(user.getId()); //创建人
			signedDto.setUserCode(user.getUserCode()); //经纪人code
			signedDto.setDelFlag(DelFlagEnum.UNDEL.getNo()); //是否删除
			signedDto.setUpdateUserId(user.getId()); //修改人
			signedDto.setUpdateTime(new Date()); //修改时间
			signedDto.setDidTime(sdf.parse(model.getDidTime()));  //签约日期
			signedDto.setCheckDate(signedDto.getDidTime());	//审核日期
			Response<SignedDto> resSigned =  signedServiceFacade.save(signedDto);
			if(resSigned.isSuccess()) {
				SignedDto dto = resSigned.getEntity();
				//修改房间状态
				updateRoomInfo(dto.getRoomId(), RoomStatusEnum.SIGN.getNo());
				//经纪人信息
				saveAgent(dto.getId(), projectId, pro.getProjectCode(), dto.getDealCategory(), 
						dto.getMerchantId(), userId, userCode, user.getId(), RelationTypeEnum.SIGNED.getNo());
				//保存待收信息
				String isHaveSignedAmount = "1"; //是否已收签约金，默认为否
				if("是".equals(model.getIsHaveSubscribeAmount())) {
					isHaveSignedAmount = "0";
				}
				SubscribeDto subDto = new SubscribeDto();
				subDto.setId(dto.getId());
				subDto.setDepositReceivable(dto.getSignAmount());
				subDto.setCustomerId(customerId);
				subDto.setRoomId(roomId);
				subDto.setMerchantId(dto.getMerchantId());
				subDto.setUserCode(userCode);
				subDto.setAccessCode(dto.getAccessCode());
				subDto.setCreateUserId(dto.getCreateUserId());
				subDto.setSubscribeDate(dto.getDidTime());
				saveNeedReceiveRefund(subDto, isHaveSignedAmount, userId, "1");
				//更新客户信息
				updateCustomerInfo(customerId, model.getCustomerName(), resultMap.get("documentType").toString(), 
						model.getDocumentNumber(), model.getContactAddress(), model.getPostcode());
				//签约房源变更记录
				signedRoomChangeHistory(dto);
			}
		}
		//保存导入错误的信息
		String batchId = UUID.randomUUID().toString(); //批次号
		if(errorList.size()>0){
			saveErrorInfo(errorList, user.getId(), user.getMerchantId(), batchId);
		}
		CustomerImportVo ci = new CustomerImportVo();
		ci.setSuccessCount(list.size() - errorList.size());
		ci.setErrorCount(errorList.size());
		ci.setBatchId(batchId);
		response.success(ci);
		return response;
	}
	
	/**
	 * 获取价格方案
	 * @param roomId
	 * @param buildingArea
	 * @param innerArea
	 * @return
	 */
	private ProjectRoomPriceDto getPriceSchemeDetail(Long roomId, BigDecimal buildingArea, BigDecimal innerArea){
		ProjectRoomPriceDto prpd = new ProjectRoomPriceDto();
		Response<PriceSchemeDetail> resPrice = priceSchemeDetailServiceFacade.selectEntityByRoomId(roomId);
		if (resPrice.isSuccess() && null != resPrice.getEntity()) {
			PriceSchemeDetail priceSchemeDetail = resPrice.getEntity();
			prpd.setSetPrice(priceSchemeDetail.getSetPrice());
			prpd.setUnitPrice(priceSchemeDetail.getUnitPrice());
			prpd.setTotalPrice(priceSchemeDetail.getTotalPrice());
			prpd.setDiscountRate(priceSchemeDetail.getDiscountRate()==null?new BigDecimal("0"):priceSchemeDetail.getDiscountRate());
			prpd.setFloatingRange(priceSchemeDetail.getFloatingRange());
			//查询计价方式
			Response<PriceScheme> resScheme = priceSchemeServiceFacade.findById(priceSchemeDetail.getPriceSchemeId());
			if (resScheme.isSuccess() && null != resScheme.getEntity()) {
				PriceScheme priceScheme = resScheme.getEntity();
				String valuationType = priceScheme.getValuationType();
				prpd.setValuationType(valuationType);
				if (valuationType.equals("1")) {
					// 计价面积=建筑面积
					prpd.setBillingArea(buildingArea);
					//折前单价=单价
					prpd.setCalculateUnitPrice(priceSchemeDetail.getUnitPrice());
				} else if (valuationType.equals("2")) {
					// 计价面积=套内面积
					prpd.setBillingArea(innerArea);
					//折前单价=套内单价
					prpd.setCalculateUnitPrice(priceSchemeDetail.getUnitPrice());
				} else {
					// 计价面积=1
					prpd.setBillingArea(new BigDecimal(1));
					//折前单价=0
					prpd.setCalculateUnitPrice(BigDecimal.ZERO);
				}
				if(priceScheme.getFloorType().equals("0")){
					prpd.setDiscountAmount(priceSchemeDetail.getUnitPrice());
					prpd.setDiscountTotalAmount(priceSchemeDetail.getTotalPrice());
					//prpd.setDiscountRate(new BigDecimal("0.00"));
				}else if(priceScheme.getFloorType().equals("1")){
					//设置折后单价=折前单价格*折扣
					double discountAmount=0;
					if(null!=prpd.getCalculateUnitPrice() && prpd.getDiscountRate().compareTo(new BigDecimal("0"))!=0){
						discountAmount=MathUtil.divide(prpd.getCalculateUnitPrice().multiply(prpd.getDiscountRate()), new BigDecimal("100"),2);	
					}else if(null!=prpd.getCalculateUnitPrice()&& prpd.getDiscountRate().compareTo(new BigDecimal("0"))==0){
						discountAmount=new Double(prpd.getCalculateUnitPrice().toString());
					}
					prpd.setDiscountAmount(new BigDecimal(discountAmount));
					//设置折后总价=折前总价*折扣
					double discountTotalAmount=0;
					if(null!=prpd.getTotalPrice() && prpd.getDiscountRate().compareTo(new BigDecimal("0"))!=0){
						discountTotalAmount=MathUtil.divide(prpd.getTotalPrice().multiply(prpd.getDiscountRate()), new BigDecimal("100"),2);	
					}else if(null!=prpd.getTotalPrice()&& prpd.getDiscountRate().compareTo(new BigDecimal("0"))==0){
						discountTotalAmount=new Double(prpd.getTotalPrice().toString());
					}
					prpd.setDiscountTotalAmount(new BigDecimal(discountTotalAmount));
				}
				prpd.setFloorType(priceScheme.getFloorType());
			}
			
		}
		return prpd;
	}
	
	/**
	 * 获取项目信息
	 */
	private Project getProjectInfo(Long projectId){
		Response<Project> resPro = projectServiceFacade.findById(projectId);
		if(!resPro.isSuccess() || resPro.getEntity() == null) {
			return null;
		}
		return resPro.getEntity();
	}
	
	/**
	 * 保存导入错误的信息
	 */
	private void saveErrorInfo(List<MarketingModel> errorList, Long userId, Long merchantId, String batchId) {
		List<CustomerError> list = new ArrayList<CustomerError>();
		for(MarketingModel mt : errorList){
			String cmStr = JSON.toJSONString(mt);
			JSONObject object=JSONObject.parseObject(cmStr);
			CustomerError ce=new CustomerError();
			ce.setBatchId(batchId);
			ce.setCreateUserId(userId);
			ce.setMerchantId(merchantId);
			ce.setCreateTime(new Date());
			ce.setUpdateTime(new Date());
			ce.setDelFlag("0");
			ce.setRowData(object.toJSONString());
			list.add(ce);
		}
		customerErrorServiceFacade.insertByBatch(list);
	}
	
	/**
	 * 校验认购字段
	 * @param model
	 * @param i 计数器，计算当前行数
	 * @return
	 */
	private Map<String, Object> validateSubscribeModel(MarketingModel model, Long projectId, int type){
		//先校验公共字段
		Map<String, Object> resultMap = validateModel(model, projectId, type);
		
		StringBuffer error = new StringBuffer("");
		//保存公共字段的错误日志
		if(resultMap.get("error") != null) {
			error.append(resultMap.get("error"));
		}
		if(StringUtils.isBlank(model.getDepositReceivable())) {
			error.append("应收认购金不能为空；");
		} else {
			resultMap.put("depositReceivable", model.getDepositReceivable());
		}
		if(StringUtils.isBlank(model.getSubscribeDate())) {
			error.append("认购日期不能为空；");
		} else {
			resultMap.put("subscribeDate", model.getSubscribeDate());
		}
		if(StringUtils.isBlank(model.getConversionSignDate())) {
			error.append("认购转签约不能为空；");
		} else {
			resultMap.put("conversionSignDate", model.getConversionSignDate());
		}
		if(StringUtils.isBlank(model.getIsHaveSubscribeAmount())) {
			error.append("是否已收认购金不能为空；");
		} else {
			resultMap.put("isHaveSubscribeAmount", model.getIsHaveSubscribeAmount());
		}
		/*if(StringUtils.isBlank(model.getIsConversionSign())) {
			error.append("是否已转签约不能为空；");
		} else {
			resultMap.put("isConversionSign", model.getIsConversionSign());
		}*/
		//当有错误数据时，保存记录
		if(StringUtils.isNotBlank(error.toString())) {
			resultMap.put("error", error.toString());
		}
		return resultMap;
	}
	
	/**
	 * 保存经纪人信息
	 * @param subId
	 * @param userId
	 * @param userCode
	 * @param dealCategory
	 * @param projectId
	 * @param projectCode
	 * @param merchantId
	 */
	private void saveAgent(Long subId, Long projectId, String projectCode, String dealCategory, 
			Long merchantId, Long userId, String userCode, Long createUserId, String relationType) {
		TransactionRelationDto tranDto = new TransactionRelationDto();
		// 清空原经纪人
		tranDto.setBusinessId(subId);
		tranDto.setProjectId(projectId);
		tranDto.setProjectCode(projectCode);
		tranDto.setRelationType(relationType); //关联类型
		tranDto.setMerchantId(merchantId);
		transactionRelationServiceFacade.destroy(tranDto);
		// 当成交类型为单独成交或推荐成交时，修改分佣比例为100%
		if ("2".equals(dealCategory) || "1".equals(dealCategory)) {
			tranDto.setProportionCommission("100");
		}
		tranDto.setAccessCode(projectCode);
		tranDto.setRelationAgentid(userId);
		tranDto.setUserCode(userCode);
		tranDto.setCreateUserId(createUserId);
		tranDto.setDelFlag(DelFlagEnum.UNDEL.getNo());
		tranDto.setUpdateUserId(createUserId);
		tranDto.setUpdateTime(new Date());
		transactionRelationServiceFacade.save(tranDto);
	}
	
	/**
	 * 修改客户信息
	 */
	private void updateCustomerInfo(Long customerId, String customerName, String documentTypeName, String documentNumber, 
			String contactAddress, String Postcode) {
		CustomerDto customerDto = new CustomerDto();
		customerDto.setId(customerId);
		customerDto.setPeDocumentType(documentTypeName);
		customerDto.setPeDocumentNumber(documentNumber);
		customerDto.setPeContactAddress(contactAddress);
		customerDto.setPePostcode(Postcode);
		customerDto.setCustomerName(customerName);
		customerServiceFacade.updateByPrimaryKey(customerDto, true);
	}
	
	/**
	 * 保存待收信息
	 * @param subDto
	 * @param flag 是否已收款  0否 1是
	 * @param isSigned 是否为签约  0否 1是
	 * @throws Exception 
	 */
	private void saveNeedReceiveRefund(SubscribeDto subDto, String flag, Long userId, String isSigned) throws Exception {
		NeedReceiveRefundDto needReceiveRefundDto=new NeedReceiveRefundDto();
		needReceiveRefundDto.setRelationId(subDto.getId());
		needReceiveRefundDto.setTotalReceivablesAmount(subDto.getDepositReceivable());
		needReceiveRefundDto.setCustomerId(subDto.getCustomerId());
		needReceiveRefundDto.setRoomId(subDto.getRoomId());
		needReceiveRefundDto.setStatus("1"); //待售默认为未结清，如实际已结清，会在收款时自动修改 
		needReceiveRefundDto.setPostponedStatus("0");
		needReceiveRefundDto.setDocType(DocTypeEnum.COLLECTION.getNo());
		needReceiveRefundDto.setReceivablesDate(subDto.getSubscribeDate());
		if("0".equals(isSigned)) {
			needReceiveRefundDto.setBusinessType(BusinessTypeEnum.SUBSCRIBE.getNo());
			needReceiveRefundDto.setRemark("认购收款");
			needReceiveRefundDto.setHousingFundType(HousingFundTypeEnum.FUNDTYPE_3.getNo());//认购金
			needReceiveRefundDto.setBusinessFlag(BusinessFlagEnum.BUSINESSFLAG_5.getNo());
		} else {
			needReceiveRefundDto.setBusinessType(BusinessTypeEnum.SIGNED.getNo());
			needReceiveRefundDto.setRemark("签约收款");
			needReceiveRefundDto.setHousingFundType(HousingFundTypeEnum.FUNDTYPE_5.getNo());//一次性全款
			needReceiveRefundDto.setBusinessFlag(BusinessFlagEnum.BUSINESSFLAG_9.getNo());
			needReceiveRefundDto.setReceivablesFunds("一次性付款");
		}
		needReceiveRefundDto.setPostponedStatus("0");
		needReceiveRefundDto.setMerchantId(subDto.getMerchantId());
		needReceiveRefundDto.setUserCode(subDto.getUserCode());
		needReceiveRefundDto.setAccessCode(subDto.getAccessCode());
		needReceiveRefundDto.setCreateUserId(subDto.getCreateUserId());
		needReceiveRefundDto.setDelFlag("0");
		needReceiveRefundDto.setUpdateUserId(subDto.getCreateUserId());
		needReceiveRefundDto.setUpdateTime(new Date());
		Response<NeedReceiveRefundDto> resNeed = needReceiveRefundServiceFacade.save(needReceiveRefundDto);
		if(resNeed.isSuccess()) {
			//当状态为已收款时，执行收款操作
			if("0".equals(flag)) {
				saveHaveReceiveRefund(subDto, resNeed.getEntity().getId(), userId, isSigned);
			}
		}
	}
	
	/**
	 * 保存收款信息
	 * @param subDto
	 * @param needId
	 * @param userId
	 * @throws Exception
	 */
	private void saveHaveReceiveRefund(SubscribeDto subDto, Long needId, Long userId, String isSigned) throws Exception{
		ProceedsDto proceedsDto = new ProceedsDto();
		proceedsDto.setUserId(userId);
		proceedsDto.setUserCode(subDto.getUserCode());
		proceedsDto.setRelationId(subDto.getId());
		if("0".equals(isSigned)) {
			proceedsDto.setBusinessType(BusinessTypeEnum.SUBSCRIBE.getNo());
		} else {
			proceedsDto.setBusinessType(BusinessTypeEnum.SIGNED.getNo());
		}
		proceedsDto.setStatementDate(sdf.format(subDto.getSubscribeDate()));
		proceedsDto.setRealAmount(subDto.getDepositReceivable().toString());
		proceedsDto.setNeedReceiveId(needId);
		proceedsServiceFacade.receiveMoney(proceedsDto);
	}
	
	/**
	 * 修改房间状态
	 * @param roomId
	 * @param roomStatus
	 */
	private void updateRoomInfo(Long roomId, String roomStatus) {
		ProjectRoomDto dto = new ProjectRoomDto();
		dto.setId(roomId);
		dto.setRoomStatus(roomStatus);
		projectRoomServiceFacade.updateByDto(dto);
	}
	
	/**
	 * 认购房源变更记录
	 * @param subscribe
	 */
	private void subscribeRoomChangeHistory(SubscribeDto subscribe) {
		RoomChangeHistoryDto dto=new RoomChangeHistoryDto();
		dto.setRoomId(subscribe.getRoomId());
		dto.setBusinessDynamics("认购");
		if(StringUtils.isBlank(subscribe.getPayDepositCode())){
			dto.setRemark("房源由【可售】转为【认购】");
		}else{
			dto.setRemark("房源由【小定】转为【认购】");
		}
		dto.setBusinessHref("/customer/subscribe/toView?id="+subscribe.getId()+"&returnUrl=,marketing,room,index");
		dto.setMerchantId(subscribe.getMerchantId());
		dto.setAccessCode(subscribe.getAccessCode());
		dto.setCreateUserId(subscribe.getCreateUserId());
		dto.setUserCode(subscribe.getUserCode());
		dto.setDelFlag("0");
		dto.setUpdateUserId(subscribe.getUpdateUserId());
		dto.setUpdateTime(new Date());
		roomChangeHistoryServiceFacade.save(dto);
	}
	
	/**
	 * 签约房源变更记录
	 * @param signed
	 */
	private void signedRoomChangeHistory(SignedDto signed) {
		RoomChangeHistoryDto dto=new RoomChangeHistoryDto();
		dto.setRoomId(signed.getRoomId());
		dto.setBusinessDynamics("签约");
		if(signed.getSubscribeId() != null){
			dto.setRemark("房源由【认购】转为【签约】");
		}else if(signed.getPayDepositId()!=null){
			dto.setRemark("房源由【小定】转为【签约】");
		}else {
			dto.setRemark("房源由【可售】转为【签约】");
		}
		dto.setBusinessHref("/customer/signed/toView?id="+signed.getId()+"&returnUrl=,marketing,room,index");
		dto.setMerchantId(signed.getMerchantId());
		dto.setAccessCode(signed.getAccessCode());
		dto.setCreateUserId(signed.getCreateUserId());
		dto.setUserCode(signed.getUserCode());
		dto.setDelFlag("0");
		dto.setUpdateUserId(signed.getUpdateUserId());
		dto.setUpdateTime(new Date());
		roomChangeHistoryServiceFacade.save(dto);
	}
	
	/**
	 * 校验签约字段
	 * @param model
	 * @param i 计数器，计算当前行数
	 * @return
	 */
	private Map<String, Object> validateSignedModel(MarketingModel model, Long projectId, int type){
		//校验公共字段
		Map<String, Object> resultMap = validateModel(model, projectId, type);
		StringBuffer error = new StringBuffer(""); 
		//保存公共字段的错误日志
		if(resultMap.get("error") != null) {
			error.append(resultMap.get("error"));
		}
		if(StringUtils.isBlank(model.getPaymentMethod())) {
			error.append("支付方式不能为空；");
		} else {
			resultMap.put("paymentMethod", PaymentMethodEnum.getByDescription(model.getPaymentMethod()).getNo());
		}
		if(StringUtils.isBlank(model.getDidTime())) {
			error.append("签约日期不能为空；");
		} else {
			resultMap.put("didTime", model.getDidTime());
		}
		if(StringUtils.isBlank(model.getContactType())) {
			error.append("合同类型不能为空；");
		} else {
			resultMap.put("contactType", ContactTypeEnum.getByDescription(model.getContactType()).getNo());
		}
		//当有错误数据时，保存记录
		if(StringUtils.isNotBlank(error.toString())) {
			resultMap.put("error", error.toString());
		}
		return resultMap;
	}
	
	/**
	 * 校验公共字段
	 * @param model
	 * @param projectId
	 * @return
	 */
	private Map<String, Object> validateModel(MarketingModel model, Long projectId, int type){
		Map<String, Object> resultMap = new HashMap<String, Object>(16);
		StringBuffer error = new StringBuffer("");
		//判断模板类型
		String[] modelName = {"房号","房间"};
		if(type == 2) {
			modelName[0] = "车位号";
			modelName[1] = "车位";
		}
		if(StringUtils.isBlank(model.getRoomName())) {
			error.append(modelName[0]+"不能为空;");
		} else {
			//当组团不为空且时，先查询项目组团信息
			Long premisesId = null;
			if(StringUtils.isNotBlank(model.getPremisesName())){
				ProjectPremisesDto premisesDto = new ProjectPremisesDto();
				premisesDto.setProjectId(projectId);
				premisesDto.setGroupName(model.getPremisesName());
				ResponseList<ProjectPremises> resPremises = projectPremisesServiceFacade.findByDto(premisesDto);
				if(!resPremises.isSuccess() || resPremises.getEntity() == null 
						|| resPremises.getEntity().size() == 0) {
					error.append("未查询到组团；");
				} else {
					premisesId = resPremises.getEntity().get(0).getId();
				}
			}
			//当楼栋不为空时，先查询楼栋信息
			Long buildingId = null;
			if(StringUtils.isNotBlank(model.getBuildingName())){
				ProjectBuildingDto buildDto = new ProjectBuildingDto();
				buildDto.setProjectId(projectId);
				buildDto.setPremisesId(premisesId);
				buildDto.setBuildingName(model.getBuildingName());
				ResponseList<ProjectBuilding> resBuild = projectBuildingServiceFacade.findByDto(buildDto);
				if(!resBuild.isSuccess() || resBuild.getEntity() == null 
						|| resBuild.getEntity().size() == 0) {
					error.append("未查询到楼栋；");
				} else {
					buildingId = resBuild.getEntity().get(0).getId();
				}
			}
			//当单元不为空时，先查询单元信息
			Long unitId = null;
			if(StringUtils.isNotBlank(model.getUnitName())) {
				ProjectUnitDto unitDto = new ProjectUnitDto();
				unitDto.setProjectId(projectId);
				unitDto.setPremisesId(premisesId);
				unitDto.setBuildingId(buildingId);
				unitDto.setUnitName(model.getUnitName());
				ResponseList<ProjectUnit> resUnit = projectUnitServiceFacade.findByDto(unitDto);
				if(!resUnit.isSuccess() || resUnit.getEntity() == null 
						|| resUnit.getEntity().size() == 0) {
					error.append("未查询到单元；");
				} else {
					unitId = resUnit.getEntity().get(0).getId();
				}
			}
			//查询房间ID
			ProjectRoomDto roomDto = new ProjectRoomDto();
			roomDto.setBuildingId(buildingId);
			roomDto.setPremisesId(premisesId);
			roomDto.setUnitId(unitId);
			roomDto.setRoomName(model.getRoomName());
			roomDto.setProjectId(projectId);
			ResponseList<ProjectRoom> resRoom = projectRoomServiceFacade.findByDto(roomDto);
			if(!resRoom.isSuccess() || resRoom.getEntity() == null 
					|| resRoom.getEntity().size() == 0) {
				error.append("未查询到"+modelName[1]+"；");
			} else {
				for(ProjectRoom room : resRoom.getEntity()) {
					resultMap.put("roomId", room.getId());
					resultMap.put("calculateArea", room.getBuildingArea());
					resultMap.put("innerArea", room.getInnerArea());
				}
			}
		}
		if(StringUtils.isBlank(model.getCustomerName()) 
				|| StringUtils.isBlank(model.getCustomerPhone())) {
			error.append("客户姓名和手机号不能为空；");
		} else {
			Object obj = getCache(projectId+"_"+model.getCustomerName()+"_"+model.getCustomerPhone());
			if(obj == null) {
				error.append("未查询到客户；");
			} else {
				resultMap.put("customerId", obj);
			}
		}
		if(StringUtils.isBlank(model.getDocumentType())) {
			error.append("证件类型不能为空；");
		} else {
			resultMap.put("documentType", getCache(projectId+"_"+model.getDocumentType()));
		}
		if(StringUtils.isBlank(model.getDocumentNumber())) {
			error.append("证件号码不能为空；");
		} else {
			if("身份证".equals(model.getDocumentType()) && 
					!VerifyIDNumber.verifyIDCard(model.getDocumentNumber())) {
				error.append("身份证号码不正确；");
			} else if ("营业执照".equals(model.getDocumentType()) && 
					!VerifyIDNumber.verifyBusinessLicense(model.getDocumentNumber())) {
				error.append("营业执照号码不正确；");
			} else {
				resultMap.put("documentNumber", model.getDocumentNumber());
			}
		}
		if(StringUtils.isBlank(model.getPostcode())) {
			error.append("邮编不能为空；");
		} else {
			resultMap.put("postcode", model.getPostcode());
		}
		if(StringUtils.isBlank(model.getContactAddress())) {
			error.append("邮寄地址不能为空；");
		} else {
			resultMap.put("contactAddress", model.getContactAddress());
		}
		if(StringUtils.isBlank(model.getDealCategory())) {
			error.append("成交类别不能为空；");
		} else {
			resultMap.put("dealCategory", DealCategoryEnum.getByDescription(model.getDealCategory()).getNo());
		}
		if(StringUtils.isBlank(model.getAgentName())) {
			error.append("经纪人不能为空；");
		} else {
			Object obj = getCache(model.getAgentName());
			if(obj == null) {
				error.append("未查询到经纪人；");
			} else {
				User user = (User) obj;
				resultMap.put("userCode", user.getUserCode());
				resultMap.put("userId", user.getId());
			}
		}
		if(StringUtils.isBlank(model.getProportionCommission())) {
			error.append("分佣比例不能为空；");
		} else {
			resultMap.put("proportionCommission", model.getProportionCommission());
		}
		if(StringUtils.isBlank(model.getDiscountAfterPrice())) {
			error.append("折后总价不能为空；");
		} else {
			resultMap.put("discountAfterPrice", model.getDiscountAfterPrice());
		}
		if(StringUtils.isNotBlank(error.toString())) {
			resultMap.put("error", error.toString());
		}
		return resultMap;
	}
	
	/**
	 * 获取客户列表,并写入缓存
	 * @param projectId
	 */
	private void getCustomerList(Long projectId) {
		CustomerDto cusDto = new CustomerDto();
		cusDto.setProjectId(projectId);
		cusDto.setDelFlag(DelFlagEnum.UNDEL.getNo());
		ResponseList<Customer> resCus = customerServiceFacade.findByDto(cusDto);
		if(resCus.isSuccess()) {
			for(Customer cus : resCus.getEntity()) {
				setCache(cus.getProjectId()+"_"+cus.getCustomerName()+"_"+cus.getCustomerPhone(), cus.getId());
			}
		}
	}
	
	/**
	 * 获取经纪人列表,并写入缓存
	 * @param merchantId
	 */
	private void getUserList(Long merchantId) {
		UserDto userDto = new UserDto();
		userDto.setMerchantId(merchantId);
		userDto.setUserStatus(UserStatusEnum.IN_USE.getNo());
		userDto.setDelFlag(DelFlagEnum.UNDEL.getNo());
		ResponseList<User> resUser = userServiceFacade.findByDto(userDto);
		if(resUser.isSuccess()) {
			for(User user : resUser.getEntity()) {
				setCache(user.getUserName(), user);
			}
		}
	}
	
	/**
	 * 获取证件类型ID,并写入缓存
	 * @param projectId
	 */
	private void getDocumentTypeId(Long projectId) {
		BaseCodeTypeDto typeDto = new BaseCodeTypeDto();
		typeDto.setProjectId(projectId);
		typeDto.setTypeName("证件类型");
		typeDto.setDelFlag(DelFlagEnum.UNDEL.getNo());
		ResponseList<BaseCodeType> resType = baseCodeTypeServiceFacade.findByDto(typeDto);
		if(resType.isSuccess()) {
			for(BaseCodeType type : resType.getEntity()) {
				BaseCodeValueDto valueDto = new BaseCodeValueDto();
				valueDto.setProjectId(projectId);
				valueDto.setTypeId(type.getId());
				valueDto.setDelFlag(DelFlagEnum.UNDEL.getNo());
				ResponseList<BaseCodeValue> resValue = baseCodeValueServiceFacade.findByDto(valueDto);
				if(resValue.isSuccess()) {
					for(BaseCodeValue value : resValue.getEntity()) {
						setCache(projectId+"_"+value.getCodeName(), value.getId());
					}
				}
			}
		}
	}
	
	/**
	 * 写入缓存
	 * @param key
	 * @param value
	 */
	private void setCache(String key, Object value){
		cacheUtils.put(EhcacheConstant.ACTIVE_SESSIONS_CACHE, key, value);
	}
	/**
	 * 获取缓存
	 */
	private Object getCache(String key){
		Object cache = cacheUtils.get(EhcacheConstant.ACTIVE_SESSIONS_CACHE, key);
		return cache;
	}
	/**
	 * 清除缓存
	 */
	private void delCache(String key){
		cacheUtils.remove(EhcacheConstant.ACTIVE_SESSIONS_CACHE, key);
	}
}
